package com.mycamera;


import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Point;
import android.graphics.RectF;
import android.graphics.SurfaceTexture;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.CaptureResult;
import android.hardware.camera2.TotalCaptureResult;
import android.hardware.camera2.params.StreamConfigurationMap;
import android.media.Image;
import android.media.ImageReader;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.util.Size;
import android.util.SparseIntArray;
import android.view.LayoutInflater;
import android.view.Surface;
import android.view.TextureView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.Fragment;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

import static androidx.core.content.ContextCompat.checkSelfPermission;


public class Camera2BasicFragment extends Fragment
        implements View.OnClickListener, ActivityCompat.OnRequestPermissionsResultCallback {

    /**
     * Conversion from screen rotation to JPEG orientation.
     * 从屏幕旋转到JPEG方向的转换
     */
    private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
    private static final int REQUSET_CAMERA_PERMISSION = 1;
    private static final String FRAGMENT_DIALOG = "dialog";

    //权限申请

    private static final String[] permission = new String[]{
            //相机、读、写、录音权限
            Manifest.permission.CAMERA,
            Manifest.permission.READ_EXTERNAL_STORAGE,
            Manifest.permission.WRITE_EXTERNAL_STORAGE,
            Manifest.permission.RECORD_AUDIO,
    };



    static {
        ORIENTATIONS.append(Surface.ROTATION_0, 90);
        ORIENTATIONS.append(Surface.ROTATION_90, 0);
        ORIENTATIONS.append(Surface.ROTATION_180, 270);
        ORIENTATIONS.append(Surface.ROTATION_270, 180);
    }
    private ImageView mPicture;
    private Uri mImageUri, mImageUriFromFile;
    private static final String FILE_PROVIDER_AUTHORITY = "cn.fonxnickel.officialcamerademo.fileprovider";

    /**
     * 标签{@link Log}.
     */
    private static final String TAG = "Camera2BasicFragment";
    /**
     * 相机状态：显示相机预览
     */
    private static final int STATE_PREVIEW = 0;
    /**
     * 相机状态：等待锁定焦点
     */
    private static final int STATE_WAITING_LOCK = 1;
    /**
     * 相机状态：等待曝光到预捕获状态
     */
    private static final int STATE_WAITING_PRECAPTURE = 2;
    /**
     * 相机状态：等待曝光，而不是预先捕捉
     */
    private static final int STATE_WAITING_NON_PRECAPTURE = 3;
    /**
     * 相机状态：已拍照
     */
    private static final int STATE_PICTURE_TAKEN = 4;
    /**
     * Camera2 API 保证的最大预览宽度
     */
    private static final int MAX_PREVIEW_WIDTH = 1920;
    /**
     * Camera2 API 保证的最大预览高度
     */
    private static final int MAX_PREVIEW_HEIGHT = 1080;
    /**
     * {@link TextureView.SurfaceTextureListener}在{@link TextureView}中处理多个生命周期事件。
     */
    private final TextureView.SurfaceTextureListener mSurfaceTextureListener
            = new TextureView.SurfaceTextureListener() {
        @Override
        public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
            openCamera(width, height);
        }

        @Override
        public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
            configureTransform(width, height);
        }

        @Override
        public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
            return true;
        }

        @Override
        public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {

        }
    };
    /**
     * 当前{@link android.hardware.camera2.CameraDevice}的ID
     */
    private String mCameraId;
    private int frontCameraIndex;
    private int backCameraIndex;

    /**
     * {@link AutoFitTextureView}用于相机预览
     */
    private AutoFitTextureView mTextureView;
    /**
     * {@link CameraCaptureSession}用于相机预览
     */
    private CameraCaptureSession mCaptureSession;
    /**
     * 对打开{@link CameraDevice}的引用
     */
    private CameraDevice mCameraDevice;
    /**
     * 相机预览的{@link Size}
     */
    private Size mPreviewSize;
    /**
     * 当{@link CameraDevice}改变其状态时调用{@link CameraDevice.StateCallback}
     */
    private final CameraDevice.StateCallback mStateCallback = new CameraDevice.StateCallback() {
        @Override
        public void onOpened(@NonNull CameraDevice cameraDevice) {
            //这个方法在摄像机被打开时调用，我们从这里开始预览。
            mCameraOpenCloseLock.release();
            mCameraDevice = cameraDevice;
            createCameraPreviewSession();
        }

        @Override
        public void onDisconnected(@NonNull CameraDevice cameraDevice) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
        }

        @Override
        public void onError(@NonNull CameraDevice cameraDevice, int error) {
            mCameraOpenCloseLock.release();
            cameraDevice.close();
            mCameraDevice = null;
            Activity activity = getActivity();
            if (null != activity) {
                activity.finish();
            }

        }
    };


    /**
     * 用于运行不应该阻塞UI的任务的额外线程。
     */
    private HandlerThread mBackgroundThread;
    /**
     * 用于在后台运任务的{@link Handler}。
     */
    private Handler mBackgroundHandler;
    /**
     * {@link ImageReader}处理静态图像捕获。
     */
    private ImageReader mImageReader;
    /**
     * 图片传输文件
     */
    private File mFile;
    /*
     * 这是一个{@link ImageReader}的回调对象。"onImageAvailable"将在静止图像准备保存时被调用。
     */
    private final ImageReader.OnImageAvailableListener mOnImageAvailableListener
            = new ImageReader.OnImageAvailableListener() {
        @Override
        public void onImageAvailable(ImageReader reader) {
//            Log.d(TAG, "创建图片回调对象");
            mBackgroundHandler.post(new ImageSaver(reader.acquireNextImage(), mFile));
        }
    };
    /**
     * {@link CaptureRequest.Builder}的相机预览
     */
    private CaptureRequest.Builder mPreviewRequestBuilder;
    /**
     * {@link CaptureRequest}生成 {@link #mPreviewRequestBuilder}
     */
    private CaptureRequest mPreviewRequest;
    /**
     * 用于拍照的相机的当前状态
     */
    private int mState = STATE_PREVIEW;
    /**
     * {@link Semaphore}用来在关闭摄像头之前阻止应用退出。
     */
    private Semaphore mCameraOpenCloseLock = new Semaphore(1);
    /**
     * 当前摄像设备是否支持Flash。
     */
    private boolean mFlashSuported;
    /**
     * 摄像头传感器的方向
     */
    private int mSensorOrientation;
    /**
     * {@link CameraCaptureSession.CaptureCallback}处理与JPEG捕获相关的事件。
     */
    private CameraCaptureSession.CaptureCallback mCaptureCallback
            = new CameraCaptureSession.CaptureCallback() {

        private void process(CaptureResult result) {
            switch (mState) {
                case STATE_PREVIEW: {
                    //摄像头预览正常时，我们无事可做。
//                    Log.d(TAG, "在预览");
                    break;
                }
                case STATE_WAITING_LOCK: {
                    Integer afState = result.get(CaptureResult.CONTROL_AF_STATE);
//                    Log.d(TAG, "在聚焦");
                    if (afState == null || afState == 0) {
//                        Log.d(TAG, "af空");
                        captureStillPicture();
                    } else if (CaptureResult.CONTROL_AF_STATE_FOCUSED_LOCKED == afState ||
                            CaptureResult.CONTROL_AF_STATE_NOT_FOCUSED_LOCKED == afState) {
                        Log.d(TAG, "1");
                        //CONTROL_AE_STATE在某些设备上可以为空
                        Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                        if (aeState == null ||
                                aeState == CaptureResult.CONTROL_AE_STATE_CONVERGED) {
                            mState = STATE_PICTURE_TAKEN;
                            captureStillPicture();
                            Log.d(TAG, "已拍照");
                        } else {
                            runPrecaptureSequence();
                            Log.d(TAG, "2");
                        }
                    }
                    Log.d(TAG, "结束");
                    break;
                }
                case STATE_WAITING_PRECAPTURE: {
                    Log.d(TAG, "在曝光");
                    //CONTROL_AE_STATE在某些设备上可以为空
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null ||
                            aeState == CaptureResult.CONTROL_AE_STATE_PRECAPTURE ||
                            aeState == CaptureRequest.CONTROL_AE_STATE_FLASH_REQUIRED) {
                        mState = STATE_WAITING_NON_PRECAPTURE;
                    }
                    break;
                }
                case STATE_WAITING_NON_PRECAPTURE: {
                    //CONTROL_AE_STATE在某些设备上可以为空
                    Log.d(TAG, "不捕捉");
                    Integer aeState = result.get(CaptureResult.CONTROL_AE_STATE);
                    if (aeState == null ||
                            aeState != CaptureResult.CONTROL_AE_STATE_PRECAPTURE) {
                        mState = STATE_PICTURE_TAKEN;
                        captureStillPicture();
                    }
                    break;
                }

            }
        }

        @Override
        public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
            process(partialResult);
        }

        @Override
        public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
            process(result);
        }
    };

    /**
     * 在UI线程上显示一个{@link Toast}。
     *
     * @param text The message to show
     */
    private void showToast(final String text) {
        final Activity activity = getActivity();
        if (activity != null) {
            activity.runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(activity, text, Toast.LENGTH_SHORT).show();
                }
            });
        }
    }

    /**
     * 给定摄像头支持的{@code Size}的{@code choices}，选择最小的一个
     * 至少和各自的纹理视图大小一样大，最多和各自的Max大小一样大，
     * 并且其宽高比与指定的值匹配。如果不存在这样的大小，
     * 则选择最大的一个，最大不超过相应的最大大小，其长宽比与指定的值匹配。
     *
     * @param choices           相机为预期输出类支持的大小列表
     * @param textureViewWidth  纹理视图相对于传感器坐标的宽度
     * @param textureViewHeight 纹理视图相对于传感器坐标的高度
     * @param maxWidth          可以选择的最大宽度
     * @param maxHeight         可以选择的最大高度
     * @param aspectRatio       高宽比
     * @return The optimal {@code Size}, or an arbitrary one if none were big enough
     * 最佳的{@code Size}，或者任意一个(如果没有足够大的话)
     */
    private static Size chooseOptimalSize(Size[] choices, int textureViewWidth,
                                          int textureViewHeight, int maxWidth,
                                          int maxHeight, Size aspectRatio) {
        // 收集支持的分辨率，至少与预览Surface一样大
        List<Size> bigEnough = new ArrayList<>();
        //收集比预览版Surface更小的分辨率
        List<Size> notBigEnough = new ArrayList<>();
        int w = aspectRatio.getWidth();
        int h = aspectRatio.getHeight();
        for (Size option : choices) {
            if (option.getWidth() <= maxWidth && option.getHeight() <= maxHeight &&
                    option.getHeight() == option.getWidth() * h / w) {
                if (option.getWidth() >= textureViewWidth &&
                        option.getHeight() >= textureViewHeight) {
                    bigEnough.add(option);
                } else {
                    notBigEnough.add(option);
                }
            }
        }
        //选一个足够大的最小的。如果没有足够大的，那就从那些不够大的中挑出最大的。
        if (bigEnough.size() > 0) {
            return Collections.min(bigEnough, new CompareSizesByArea());
        } else if (notBigEnough.size() > 0) {
            return Collections.max(notBigEnough, new CompareSizesByArea());
        } else {
            Log.e(TAG, "Couldn't find any suitable preview size");
            return choices[0];
        }


    }

    public static Camera2BasicFragment newInstance() {
        return new Camera2BasicFragment();
    }

    public static boolean checkPermission(Activity activity) {
        if (isPermissionGranted(activity)) {
            return true;
        } else {
            ActivityCompat.requestPermissions(activity, permission, REQUSET_CAMERA_PERMISSION);
            return false;
        }
    }

    public static boolean isPermissionGranted(Activity activity) {
        if (Build.VERSION.SDK_INT >= 23) {
            for (int i = 0; i < permission.length; i++) {
                int checkPermission = ContextCompat.checkSelfPermission(activity, permission[i]);//动态申请权限
                if (checkPermission != PackageManager.PERMISSION_GRANTED) {//已获得权限
                    return false;
                }
            }
            return true;
        } else {
            return true;
        }
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        return inflater.inflate(R.layout.fragment_camera2_basic, container, false);
    }

    @Override
    public void onViewCreated(final View view, Bundle savedInstanceState) {
        mPicture = view.findViewById(R.id.iv_picture);
        view.findViewById(R.id.picture).setOnClickListener(this);//点击事件
        view.findViewById(R.id.iv_picture).setOnClickListener(this);//点击事件
        view.findViewById(R.id.settings).setOnClickListener(this);//点击事件
        view.findViewById(R.id.trigger).setOnClickListener(this);//点击事件
        mTextureView = (AutoFitTextureView) view.findViewById(R.id.texture);
    }

    @Override
    public void onActivityCreated(Bundle savedInstanceState) {
        super.onActivityCreated(savedInstanceState);
        mFile = createImageFile();//创建用来保存照片的文件


    }

    /**
     * 创建用来存储图片的文件，以时间来命名就不会产生命名冲突
     *
     * @return 创建的图片文件
     */
    private File createImageFile() {
        @SuppressLint("SimpleDateFormat")
        String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
        String imageFileName = "JPEG_" + timeStamp + "_";
        File storageDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES);
//        File storageDir = getSDPath(context);
        File imageFile = null;
        try {
            imageFile = File.createTempFile(imageFileName, ".jpg", storageDir);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return imageFile;
    }

    private File getSDPath(Context context){
        File sdDir = null;
        boolean sdCardExist = Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED);//判断sd卡是否存在
        if(sdCardExist){
            if (Build.VERSION.SDK_INT >=  29){
                sdDir = context.getExternalFilesDir(null);
            }else {
                sdDir = Environment.getExternalStorageDirectory();//获取SD卡根目录
            }
        }else {
            sdDir = Environment.getRootDirectory();//获取根目录
        }
        return sdDir;
    }

    @Override
    public void onResume() {
        super.onResume();
        startBackgroundThread();

        //当屏幕被关闭并重新打开时，SurfaceTexture已经可用，而"onSurfaceTextureAvailable"将不会被调用。
        // 在这种情况下，我们可以打开一个相机并从这里开始预览
        // (否则，我们等待表面在SurfaceTextureListener中准备好)。
        if (mTextureView.isAvailable()) {
            openCamera(mTextureView.getWidth(), mTextureView.getHeight());
        } else {
            mTextureView.setSurfaceTextureListener(mSurfaceTextureListener);
        }

    }

    @Override
    public void onPause() {
        closeCamera();
        stopBackgroudThread();
        super.onPause();
    }

    @SuppressLint("NewApi")
    private void requestCameraPermission() {
        checkPermission(getActivity());
//        if (shouldShowRequestPermissionRationale(Manifest.permission.CAMERA)) {
//            new ConfirmationDialog().show(getChildFragmentManager(), FRAGMENT_DIALOG);
//        } else {
//            requestPermissions(new String[]{Manifest.permission.CAMERA}, REQUSET_CAMERA_PERMISSION);
//        }
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {

        if (requestCode == REQUSET_CAMERA_PERMISSION) {
            if (grantResults.length != 1 || grantResults[0] != PackageManager.PERMISSION_GRANTED) {
                ErrorDialog.newInstance(getString(R.string.request_permission))
                        .show(getChildFragmentManager(), FRAGMENT_DIALOG);
            }
        } else {
            super.onRequestPermissionsResult(requestCode, permissions, grantResults);
        }

    }

    /**
     * 设置与相机相关的成员变量。
     *
     * @param width  The width of available size for camera preview
     *               相机预览可用尺寸的宽度
     * @param height The height of available size for camera preview
     *               相机预览可用尺寸的高度
     */
    @SuppressWarnings("SuspiciousNameXombination")
    private void setUpCameraOutputs(int width, int height) {
        Activity activity = getActivity();
        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            for (String camerId : manager.getCameraIdList()) {
                CameraCharacteristics characteristics
                        = manager.getCameraCharacteristics(camerId);
                //在这个示例中，我们没有使用前置摄像头。
                Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
                if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
                    frontCameraIndex = facing;
                }else if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
                    backCameraIndex = facing;
                }

                StreamConfigurationMap map = characteristics.get(
                        CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
                if (map == null) {
                    continue;
                }
                Size largest = Collections.max(
                        Arrays.asList(map.getOutputSizes(ImageFormat.JPEG)),
                        new CompareSizesByArea());
                Log.d(TAG, "获取两张照片");
                mImageReader = ImageReader.newInstance(largest.getWidth(), largest.getHeight(),
                        ImageFormat.JPEG, 2);
                Log.d(TAG, "创建读取");
                mImageReader.setOnImageAvailableListener(
                        mOnImageAvailableListener, mBackgroundHandler);

                //看看我们是否需要交换尺寸以获得相对于传感器坐标的预览尺寸。
                int displayRotation = activity.getWindowManager().getDefaultDisplay().getRotation();

                mSensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
                boolean swappedDimensions = false;
                switch (displayRotation) {
                    case Surface.ROTATION_0:
                    case Surface.ROTATION_180:
                        if (mSensorOrientation == 90 || mSensorOrientation == 270) {
                            swappedDimensions = true;
                        }
                        break;
                    case Surface.ROTATION_90:
                    case Surface.ROTATION_270:
                        if (mSensorOrientation == 0 || mSensorOrientation == 180) {
                            swappedDimensions = true;
                        }
                        break;
                    default:
                        Log.e(TAG, "Display rotation is invalid:" + displayRotation);
                }

                Point displaySize = new Point();
                activity.getWindowManager().getDefaultDisplay().getSize(displaySize);
                int rotatedPreviewWidth = width;
                int rotatedPreviewHeight = height;
                int maxPreviewWidth = displaySize.x;
                int maxPreviewHeight = displaySize.y;

                if (swappedDimensions) {
                    rotatedPreviewWidth = height;
                    rotatedPreviewHeight = width;
                    maxPreviewWidth = displaySize.y;
                    maxPreviewHeight = displaySize.x;
                }

                if (maxPreviewWidth > MAX_PREVIEW_WIDTH) {
                    maxPreviewWidth = MAX_PREVIEW_WIDTH;
                }

                if (maxPreviewHeight > MAX_PREVIEW_HEIGHT) {
                    maxPreviewHeight = MAX_PREVIEW_HEIGHT;
                }

                //危险,W.R.!尝试使用过大的预览尺寸可能会超过相机总线的带宽限制，导致华丽的预览，
                // 但存储的垃圾捕获数据。
                mPreviewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
                        rotatedPreviewWidth, rotatedPreviewHeight, maxPreviewWidth,
                        maxPreviewHeight, largest);

                //我们将TextureView的宽高比与我们选择的预览大小相匹配。
                int orientation = getResources().getConfiguration().orientation;
                if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
                    mTextureView.setAspectRatio(
                            mPreviewSize.getWidth(), mPreviewSize.getHeight());
                } else {
                    mTextureView.setAspectRatio(
                            mPreviewSize.getHeight(), mPreviewSize.getWidth());
                }

                //检查是否支持flash。
                Boolean available = characteristics.get(CameraCharacteristics.FLASH_INFO_AVAILABLE);
                mFlashSuported = available == null ? false : available;

                Log.d(TAG,camerId+"-----------");
                mCameraId = camerId;
                return;

            }
        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (NullPointerException e) {
            //当前，当使用Camera2API但不支持此代码运行的设备时，会抛出一个NPE。
            ErrorDialog.newInstance(getString(R.string.camera_error))
                    .show(getChildFragmentManager(), FRAGMENT_DIALOG);
        }

    }





    /**
     * 打开{@link Camera2BasicFragment#mCameraId}指定的相机
     */
    private void openCamera(int width, int height) {
        if (checkSelfPermission(getActivity(), Manifest.permission.CAMERA)
                != PackageManager.PERMISSION_GRANTED) {
            requestCameraPermission();
            return;
        }
        setUpCameraOutputs(width, height);
        configureTransform(width, height);
        Activity activity = getActivity();
        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
        try {
            if (!mCameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                throw new RuntimeException("Time out waiting to lock camera opening.");
            }
            manager.openCamera(mCameraId, mStateCallback, mBackgroundHandler);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted while trying to lock camera opening.", e);
        }
    }

    /**
     * 关闭当前的{@link CameraDevice}。
     */
    private void closeCamera() {
        try {
            mCameraOpenCloseLock.acquire();
            if (null != mCaptureSession) {
                mCaptureSession.close();
                mCaptureSession = null;
            }
            if (null != mCameraDevice) {
                mCameraDevice.close();
                mCameraDevice = null;
            }
            if (null != mImageReader) {
                mImageReader.close();
                mImageReader = null;
            }

        } catch (InterruptedException e) {
            throw new RuntimeException("Interrupted while trying to lock camera closing.", e);
        } finally {
            mCameraOpenCloseLock.release();
        }
    }

    /**
     * 启动一个后台线程和它的{@link Handler}。
     */
    private void startBackgroundThread() {
        mBackgroundThread = new HandlerThread("CameraBackground");
        mBackgroundThread.start();
        mBackgroundHandler = new Handler(mBackgroundThread.getLooper());
    }

    /**
     * 停止后台线程及其{@link处理程序}。
     */
    private void stopBackgroudThread() {
        mBackgroundThread.quitSafely();
        try {
            mBackgroundThread.join();
            mBackgroundThread = null;
            mBackgroundHandler = null;
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    /**
     * 创建一个新的{@link CameraCaptureSession}用于相机预览
     */
    private void createCameraPreviewSession() {
        try {
            SurfaceTexture texture = mTextureView.getSurfaceTexture();
            assert texture != null;

            texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());

            Surface surface = new Surface(texture);
            mPreviewRequestBuilder
                    = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
            mPreviewRequestBuilder.addTarget(surface);

            mCameraDevice.createCaptureSession(Arrays.asList(surface, mImageReader.getSurface()),
                    new CameraCaptureSession.StateCallback() {
                        @Override
                        public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
                            //相机已经关闭
                            if (null == mCameraDevice) {
                                return;
                            }
                            //当回话准备好后，我们开始显示预览
                            mCaptureSession = cameraCaptureSession;
                            try {
                                //自动聚焦应该是连续的，以便相机预览
                                mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                                        CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
                                //必要时自启动Flash
//                                setAutoFlash(mPreviewRequestBuilder);
                                //最后我们开始显示相机预览
                                mPreviewRequest = mPreviewRequestBuilder.build();
                                mCaptureSession.setRepeatingRequest(mPreviewRequest,
                                        mCaptureCallback, mBackgroundHandler);
                            } catch (CameraAccessException e) {
                                e.printStackTrace();
                            }
                        }

                        @Override
                        public void onConfigureFailed(@NonNull CameraCaptureSession session) {
                            showToast("Failed");
                        }
                    }, null
            );
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 配置必要的{@link Matrix}转换到mTextureView。
     * 这个方法应该在setUpCameraOutputs中相机预览大小确定后调用，并且mTextureView的大小是固定的。
     *
     * @param viewWidth  The width of `mTextureView`
     * @param viewHeight The height of `mTextureView`
     */
    private void configureTransform(int viewWidth, int viewHeight) {
        Activity activity = getActivity();
        if (null == mTextureView || null == mPreviewSize || null == activity) {
            return;
        }
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        Matrix matrix = new Matrix();

        RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
        RectF bufferRect = new RectF(0, 0, mPreviewSize.getHeight(), mPreviewSize.getWidth());
        float centerX = viewRect.centerX();
        float centerY = viewRect.centerY();
        if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) {
            bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());

            matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
            float scale = Math.max(
                    (float) viewHeight / mPreviewSize.getHeight(),
                    (float) viewWidth / mPreviewSize.getWidth());
            matrix.postScale(scale, scale, centerX, centerY);
            matrix.postRotate(90 * (rotation - 2), centerX, centerY);

        } else if (Surface.ROTATION_180 == rotation) {
            matrix.postRotate(1880, centerX, centerY);
        }
        mTextureView.setTransform(matrix);

    }

    /**
     * 启动静态图像捕获
     */
    private void takePicture() {
//        Log.d(TAG, "拍照");
        lockFocus();
//        Toast.makeText(CameraActivity.class,"点击拍照",Toast.LENGTH_SHORT).show();
    }

    /**
     * 打开相册
     */
    private void openAlbum() {
//        Log.d(TAG,"打开相册");
        Intent intent = new Intent(Intent.ACTION_VIEW);
//        intent.setType("vnd.android.cursor.dir/image");
        intent.setDataAndType(Uri.fromFile(mFile),"image/*");
        startActivity(intent);

        //使用Intent
//        Intent intent = new Intent(Intent.ACTION_VIEW);
////Uri mUri = Uri.parse("file://" + picFile.getPath());Android3.0以后最好不要通过该方法，存在一些小Bug
//        intent.setDataAndType(Uri.fromFile(mFile), "image/*");
//        startActivity(intent);
//        Intent openAlbumIntent = new Intent(Intent.ACTION_GET_CONTENT);
//        openAlbumIntent.setType("image/*");
//        startActivityForResult(openAlbumIntent, Activity.DEFAULT_KEYS_SHORTCUT);//打开相册
    }

    /**
     * 锁定焦点作为第一步为了静止图像捕获
     */
    private void lockFocus() {
        try {
            //这是告诉相机如何锁定聚焦
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                    CameraMetadata.CONTROL_AF_TRIGGER_START);
            //告诉#mCaptureCallback(回调)等待锁定
            mState = STATE_WAITING_LOCK;
            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                    mBackgroundHandler);
//            Log.d(TAG, "聚焦锁定");
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 运行预捕获序列已捕获静态图片。
     * 当我们在{@link #mCaptureCallback}从{@link #lockFocus()}获得响应时，应该调用这个方法。
     */
    private void runPrecaptureSequence() {
        try {

            //这只是告诉相机触发的方法。
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER,
                    CaptureRequest.CONTROL_AE_PRECAPTURE_TRIGGER_START);
            //告诉#mCaptureCallback等待设置预捕获序列
            mState = STATE_WAITING_PRECAPTURE;
            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                    mBackgroundHandler);
//            Log.d(TAG, "已捕获图片");
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }

    }


    /**
     * 捕捉一张静止的照片。
     * 当我们在{@link #mCaptureCallback}中从{@link #lockFocus()}中获得响应时，应该调用这个方法。
     */
    private void captureStillPicture() {
        try {
//            Log.d(TAG, "捕捉照片");
            final Activity activity = getActivity();
            if (null == activity || null == mCameraDevice) {
                return;
            }
            //这是我们常常用来拍照的CaptureRequest.Builder(构建器)
            final CaptureRequest.Builder captureBuilder =
                    mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
            captureBuilder.addTarget(mImageReader.getSurface());
            //使用相同的AE和AF模式的预览
            captureBuilder.set(CaptureRequest.CONTROL_AF_MODE,
                    CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
            setAutoFlash(captureBuilder);

            //取向
            int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
            captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getOrientation(rotation));

            CameraCaptureSession.CaptureCallback CaptureCallback
                    = new CameraCaptureSession.CaptureCallback() {
                @Override
                public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
                    showToast("Saved:" + mFile);
                    unlockFocus();
//                    Log.d(TAG, "解锁聚焦");
                }
            };
//            ImageRequest();
            mCaptureSession.stopRepeating();
            mCaptureSession.abortCaptures();
            mCaptureSession.capture(captureBuilder.build(), CaptureCallback, null);

        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    /**
     * 从指定的屏幕旋转中检索JPEG方向
     *
     * @param rotation The screen rotation.
     * @return The JPEG orientation (one of 0, 90, 270, and 360)
     */
    private int getOrientation(int rotation) {
        return (ORIENTATIONS.get(rotation) + mSensorOrientation + 270) % 360;
    }

    /**
     * 解锁的焦点。该方法应在静止图像捕获序列完成时调用。
     */
    private void unlockFocus() {
        try {
            //重置自动对焦触发器
            mPreviewRequestBuilder.set(CaptureRequest.CONTROL_AF_TRIGGER,
                    CameraMetadata.CONTROL_AF_TRIGGER_CANCEL);
            setAutoFlash(mPreviewRequestBuilder);
            mCaptureSession.capture(mPreviewRequestBuilder.build(), mCaptureCallback,
                    mBackgroundHandler);
            //在此之后，相机将回到正常的预览状态。
            mState = STATE_PREVIEW;
            mCaptureSession.setRepeatingRequest(mPreviewRequest, mCaptureCallback,
                    mBackgroundHandler);
        } catch (CameraAccessException e) {
            e.printStackTrace();
        }
    }

    @SuppressLint("NonConstantResourceId")
    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.iv_picture:
                openAlbum();
                Log.d(TAG,"点击相册");
                break;
            case R.id.picture:
                Log.d(TAG,"点击拍照");
                takePicture();
                break;
            case R.id.settings:
                Log.d(TAG,"点击设置");
//                openAlbum();
                break;
            case R.id.trigger:
                Log.d(TAG,"切换摄像头");
                changeCamera();
                break;

        }
    }



    //切换摄像头
    private void changeCamera() {

//        Activity activity = getActivity();
//        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
//
//        try {
//            for (String camerId : manager.getCameraIdList()) {
//                CameraCharacteristics characteristics
//                        = manager.getCameraCharacteristics(camerId);
//                Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
//                if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
//
//                }
//            }
//        } catch (CameraAccessException e) {
//            e.printStackTrace();
//        }
//
//
//        if (mCameraId.equals(CameraCharacteristics.LENS_FACING_BACK))
//            mCameraId = String.valueOf(CameraCharacteristics.LENS_FACING_FRONT);
//        else if (mCameraId.equals(CameraCharacteristics.LENS_FACING_FRONT))
//
//            mCameraId = String.valueOf(CameraCharacteristics.LENS_FACING_BACK);
//
//        Log.d(TAG,mCameraId);
//        return mCameraId;

//        Activity activity = getActivity();
//        if (mCameraDevice != null) {
//            mCameraDevice.close();
//            mCameraDevice = null;
//        }
////        mCameraId = mCameraId ^ 1;
//        if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
//            // TODO: Consider calling
//            //    ActivityCompat#requestPermissions
//            return;
//        }
//        CameraManager manager = (CameraManager) activity.getSystemService(Context.CAMERA_SERVICE);
//        try {
//            manager.openCamera(mCameraId + "", mStateCallback, mBackgroundHandler);
//        } catch (CameraAccessException e) {
//            e.printStackTrace();
//        }
    }

    private void setAutoFlash(CaptureRequest.Builder requestBuilder) {
        if (mFlashSuported) {
            requestBuilder.set(CaptureRequest.CONTROL_AE_MODE,
                    CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
        }
    }

    /**
     * 保存一个JPEG {@link图像}到指定的{@link文件}。
     */
    private class ImageSaver implements Runnable {

        /**
         * JPEG图像
         */
        private final Image mImage;
        /**
         * 我们保存图像的文件。
         */
        private final File mFile;

        /**
         * 显示缩略图
         */
        private Bitmap bitmap;

        //构造方法
        public ImageSaver(Image image, File File) {
            mImage = image;
            this.mFile = File;
        }

        @Override
        public void run() {
//            Log.d(TAG, "保存图片");
            ByteBuffer buffer = mImage.getPlanes()[0].getBuffer();
            byte[] bytes = new byte[buffer.remaining()];
            buffer.get(bytes);
            FileOutputStream output = null;
            try {
                output = new FileOutputStream(mFile);
                output.write(bytes);



                //显示图片
                BitmapFactory.Options options = new BitmapFactory.Options();
                options.inSampleSize = 2;
                bitmap = BitmapFactory.decodeByteArray(bytes,0,bytes.length,options);


            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                mImage.close();
                if (null != output) {
                    try {
                        output.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }

            mPicture.post(new Runnable() {
                @Override
                public void run() {
                    mPicture.setImageBitmap(bitmap);
                }
            });



        }


    }

    /**
     * 比较两个{@code Size}基于它们的区域。
     */
    static class CompareSizesByArea implements Comparator<Size> {
        @Override
        public int compare(Size lhs, Size rhs) {
            //我们在这里进行转换是为了确保乘法不会溢出
            return Long.signum((long) lhs.getWidth() * lhs.getHeight() -
                    (long) rhs.getWidth() * rhs.getHeight());
        }
    }


    /**
     * 显示错误消息对话框。
     */
    public static class ErrorDialog extends DialogFragment {

        private static final String ARG_MESSAGE = "message";

        public static ErrorDialog newInstance(String message) {
            ErrorDialog dialog = new ErrorDialog();
            Bundle args = new Bundle();
            args.putString(ARG_MESSAGE, message);
            dialog.setArguments(args);
            return dialog;
        }

        @NonNull
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {
            final Activity activity = getActivity();
            return new AlertDialog.Builder(activity)
                    .setMessage(getArguments().getString(ARG_MESSAGE))
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            activity.finish();
                        }
                    })
                    .create();
        }

    }

    /**
     * 显示关于相机权限的OK/Cancel确认对话框。
     */
    public static class ConfirmationDialog extends DialogFragment {
        @NonNull
        @Override
        public Dialog onCreateDialog(Bundle savedInstanceState) {

            final Fragment parent = getParentFragment();
            return new AlertDialog.Builder(getActivity())
                    .setMessage(R.string.request_permission)
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        @SuppressLint("NewApi")
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            parent.requestPermissions(new String[]{Manifest.permission.CAMERA},
                                    REQUSET_CAMERA_PERMISSION);
                        }
                    })
                    .setNegativeButton(android.R.string.cancel,
                            new DialogInterface.OnClickListener() {
                                @Override
                                public void onClick(DialogInterface dialog, int which) {
                                    Activity activity = parent.getActivity();
                                    if (activity != null) {
                                        activity.finish();
                                    }
                                }
                            })
                    .create();
        }


    }



}
